﻿using System;
using System.Collections;

namespace DataCenter.Share
{
    public delegate bool GetValueCallbackDelegate(DateTime valueTime, int flag, int fieldIndex, float value);
    public delegate bool GetArrayCallbackDelegate(DateTime valueTime, int flag, float[] array);

    public interface IIterator : IEnumerable, IEnumerator
    {        
        int Step { get; set; }
        int[] OperTypes { get; set; }
        bool MatchOperType(int flag);
    }
    
    [Serializable]
    public unsafe abstract class Binary : ICloneable, IIterator
	{
		public const byte VERSION = 0x1;
		public const byte EMPTY_FLAG = 0xFF;
        public const byte IGNORE_FLAG = 0;
		public const int MINUTES_PER_DAY = 1440;
        public const int HEADER_BUFFER_LENGTH = sizeof(byte) + sizeof(int) * 3;        

        protected static CacheStream _Stream;
        public static void CreateCache(int capacity)
        {
            if (_Stream == null)
                _Stream = new CacheStream(capacity);
        }
        public static void ReleaseCache()
        {
            if (_Stream != null)
            {
                _Stream.Close();
                _Stream.Dispose();
                _Stream = null;
            }
        }

        protected int MAX_RECORD_COUNT;
		protected byte Version;
		protected int interval;
		protected int fieldCount;
		protected int recordCount;
		protected int TotalRecordCount;        
		protected int HeaderBufferLength;
		protected int SingleBufferLength;
		protected int TotalBufferLength;        
        protected int StartTimeIndex;
        protected int EndTimeIndex;
        protected bool HasCached = false;
        protected long CachePositionIndex = -1;        
        protected byte[] buffer;

        private DateTime valueTime;

		public int Interval
		{
			get { return interval; }
		}

		public int FieldCount
		{
			get { return fieldCount; }
		}

		public int RecordCount
		{
			get { return recordCount; }
		}

        public DateTime ValueTime
        {
            get { return valueTime; }
            set { valueTime = value; }
        }

        public int BufferLength
        {
            get { return TotalBufferLength; }
        }

        public abstract byte[] GetBuffer();
        public virtual byte[] GetBuffer(DateTime startTime, DateTime endTime)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetTimeIndex(startTime);
            int endIndex = GetTimeIndex(endTime);
            int length = (endIndex - startIndex + 1) * SingleBufferLength;

            byte[] buffer0 = new byte[length];
            int offset = GetRecordIndex(startTime);
            Array.Copy(buffer, offset, buffer0, 0, length);

            return buffer0;
        }
        public virtual int GetBufferOffset(DateTime valueTime)
        {
            int timeIndex = GetTimeIndex(valueTime);
            return HEADER_BUFFER_LENGTH + timeIndex * SingleBufferLength;
        }
        public virtual int GetBufferLength(DateTime startTime, DateTime endTime)
        {
            int startIndex = GetTimeIndex(startTime);
            int endIndex = GetTimeIndex(endTime);
            return (endIndex - startIndex + 1) * SingleBufferLength;
        }

        public virtual TimePoint GetFirstPoint()
        {
            return GetFirstPoint(IGNORE_FLAG);
        }
        public virtual TimePoint GetFirstPoint(int flag)
        {
            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = HeaderBufferLength;
                    recordIndex < TotalBufferLength;
                    recordIndex += SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        byte bFlag = GetFlag(pBuffer, recordIndex);
                        if (flag > 0 && bFlag != (byte)flag)
                            continue;

                        TimePoint firstPoint = new TimePoint(fieldCount);
                        firstPoint.Time = GetTimeFromRecordIndex(recordIndex);
                        firstPoint.Flag = GetFlag(pBuffer, recordIndex);
                        firstPoint.Values = GetArray(pBuffer, recordIndex);
                        return firstPoint;
                    }
                }
            }
            return null;
        }
        public virtual TimePoint GetFirstPoint(int flag, DateTime startTime, DateTime endTime)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);

            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = startIndex;
                    recordIndex < endIndex;
                    recordIndex += SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        byte bFlag = GetFlag(pBuffer, recordIndex);
                        if (flag > 0 && bFlag != (byte)flag)
                            continue;

                        TimePoint firstPoint = new TimePoint(fieldCount);
                        firstPoint.Time = GetTimeFromRecordIndex(recordIndex);
                        firstPoint.Flag = GetFlag(pBuffer, recordIndex);
                        firstPoint.Values = GetArray(pBuffer, recordIndex);
                        return firstPoint;
                    }
                }
            }
            return null;
        }
        public virtual TimePoint GetLastPoint()
        {
            return GetLastPoint(IGNORE_FLAG);
        }
        public virtual TimePoint GetLastPoint(int flag)
        {
            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = TotalBufferLength - SingleBufferLength;
                    recordIndex >= HeaderBufferLength;
                    recordIndex -= SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        byte bFlag = GetFlag(pBuffer, recordIndex);
                        if (flag > 0 && bFlag != (byte)flag)
                            continue;

                        TimePoint lastPoint = new TimePoint(fieldCount);
                        lastPoint.Time = GetTimeFromRecordIndex(recordIndex);
                        lastPoint.Flag = GetFlag(pBuffer, recordIndex);
                        lastPoint.Values = GetArray(pBuffer, recordIndex);
                        return lastPoint;
                    }
                }
            }
            return null;
        }
        public virtual TimePoint GetLastPoint(int flag, DateTime startTime, DateTime endTime)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);

            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = endIndex;
                    recordIndex >= startIndex;
                    recordIndex -= SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        byte bFlag = GetFlag(pBuffer, recordIndex);
                        if (flag > 0 && bFlag != (byte)flag)
                            continue;

                        TimePoint lastPoint = new TimePoint(fieldCount);
                        lastPoint.Time = GetTimeFromRecordIndex(recordIndex);
                        lastPoint.Flag = GetFlag(pBuffer, recordIndex);
                        lastPoint.Values = GetArray(pBuffer, recordIndex);
                        return lastPoint;
                    }
                }
            }
            return null;
        }

        public virtual DateTime GetFirstTime()
        {
            return GetFirstTime(IGNORE_FLAG);
        }
        public virtual DateTime GetFirstTime(int flag)
        {
            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = HeaderBufferLength;
                    recordIndex < TotalBufferLength;
                    recordIndex += SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        byte bFlag = GetFlag(pBuffer, recordIndex);
                        if (flag > 0 && bFlag != (byte)flag)
                            continue;

                        DateTime firstTime = GetTimeFromRecordIndex(recordIndex);
                        return firstTime;
                    }
                }
            }
            return Utils.EMPTY_TIME;
        }
        public virtual DateTime GetFirstTime(int flag, DateTime startTime, DateTime endTime)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);

            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = startIndex;
                    recordIndex < endIndex;
                    recordIndex += SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        byte bFlag = GetFlag(pBuffer, recordIndex);
                        if (flag > 0 && bFlag != (byte)flag)
                            continue;

                        DateTime firstTime = GetTimeFromRecordIndex(recordIndex);
                        return firstTime;
                    }
                }
            }
            return Utils.EMPTY_TIME;
        }
        public virtual DateTime GetLastTime()
        {
            return GetLastTime(IGNORE_FLAG);
        }
        public virtual DateTime GetLastTime(int flag)
        {
            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = TotalBufferLength - SingleBufferLength;
                    recordIndex >= HeaderBufferLength;
                    recordIndex -= SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        byte bFlag = GetFlag(pBuffer, recordIndex);
                        if (flag > 0 && bFlag != (byte)flag)
                            continue;

                        DateTime lastTime = GetTimeFromRecordIndex(recordIndex);
                        return lastTime;
                    }
                }
            }
            return Utils.EMPTY_TIME;
        }
        public virtual DateTime GetLastTime(int flag, DateTime startTime, DateTime endTime)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);

            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = endIndex;
                    recordIndex >= startIndex;
                    recordIndex -= SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        byte bFlag = GetFlag(pBuffer, recordIndex);
                        if (flag > 0 && bFlag != (byte)flag)
                            continue;

                        DateTime lastTime = GetTimeFromRecordIndex(recordIndex);
                        return lastTime;
                    }
                }
            }
            return Utils.EMPTY_TIME;
        }

        public virtual void BeginEdit()
        {
            if (_Stream != null)
            {
                if (CachePositionIndex > -1 && HasCached)
                {
                    buffer = new byte[TotalBufferLength];
                    _Stream.Position = CachePositionIndex;
                    _Stream.Read(buffer, 0, TotalBufferLength);
                    HasCached = false;
                }
            }
        }
        public virtual void EndEdit()
        {
            if (buffer != null)
            {
                if (CachePositionIndex == -1)
                {
                    _Stream.Position = _Stream.Length;
                    CachePositionIndex = _Stream.Position;
                }
                else
                {
                    _Stream.Position = CachePositionIndex;
                }
                _Stream.Write(buffer, 0, TotalBufferLength);

                HasCached = true;
                buffer = null;
            }
        }

        public virtual bool IsRecordExist(DateTime valueTime)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                return IsRecordExist(pBuffer, recordIndex);
            }
        }
        protected virtual bool IsRecordExist(byte* pBuffer, int recordIndex)
        {
            byte flag = GetFlag(pBuffer, recordIndex);
            return (flag != EMPTY_FLAG);
        }

        public virtual void ClearFlag(DateTime startTime, DateTime endTime)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);

            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = startIndex;
                    recordIndex <= endIndex;
                    recordIndex += SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        SetFlag(pBuffer, recordIndex, EMPTY_FLAG);
                    }
                }
            }
        }
        public virtual int GetFlag(DateTime valueTime)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                return GetFlag(pBuffer, recordIndex);
            }
        }
        public virtual void SetFlag(DateTime valueTime, int flag)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                SetFlag(pBuffer, recordIndex, flag);
            }
        }
        public virtual void SetFlag(int srcFlag, int destFlag)
        {
            fixed (byte* pBuffer = buffer)
            {
                SetFlag(pBuffer, HeaderBufferLength, TotalBufferLength - SingleBufferLength, srcFlag, destFlag);
            }
        }
        public virtual void SetFlag(DateTime startTime, DateTime endTime, int srcFlag, int destFlag)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);

            fixed (byte* pBuffer = buffer)
            {
                SetFlag(pBuffer, startIndex, endIndex, srcFlag, destFlag);
            }
        }
        public virtual bool IsFlagExist(DateTime valueTime, int flag)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                return IsFlagExist(pBuffer, recordIndex, flag);
            }
        }
        protected virtual byte GetFlag(byte* pBuffer, int recordIndex)
        {
            return *(pBuffer + recordIndex);
        }
        protected virtual void SetFlag(byte* pBuffer, int recordIndex, int flag)
        {
            if (flag <= 0 || flag > 255)
                throw new ArgumentOutOfRangeException("Flag 必须在 1~255之间");

            if (*(pBuffer + recordIndex) == EMPTY_FLAG)
            {
                if (flag != EMPTY_FLAG)
                {
                    recordCount += 1;
                    if (recordCount > MAX_RECORD_COUNT)
                        throw new IndexOutOfRangeException("RecordCount 大于 MaxRecordCount");
                }
            }
            else
            {
                if (flag == EMPTY_FLAG)
                {
                    recordCount -= 1;
                    if (recordCount < 0)
                        throw new IndexOutOfRangeException("RecordCount 小于 0");
                }
            }
            *(pBuffer + recordIndex) = (byte)flag;
        }
        protected virtual void SetFlag(byte* pBuffer, int startRecordIndex, int endRecordIndex, int srcFlag, int destFlag)
        {
            for (int recordIndex = startRecordIndex;
                recordIndex <= endRecordIndex;
                recordIndex += SingleBufferLength)
            {
                if (IsFlagExist(pBuffer, recordIndex, srcFlag))
                {
                    SetFlag(pBuffer, recordIndex, destFlag);
                }
            }
        }
        protected virtual bool IsFlagExist(byte* pBuffer, int recordIndex, int flag)
        {
            byte bFlag = GetFlag(pBuffer, recordIndex);
            return (bFlag == (byte)flag);
        }

        public virtual float GetValue(DateTime valueTime)
        {
            return GetValue(valueTime, 0);
        }
        public virtual float GetValue(DateTime valueTime, int fieldIndex)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                return GetValue(pBuffer, recordIndex, fieldIndex);
            }
        }
        public virtual float[] GetArray(DateTime valueTime)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                float?[] values = GetArray(pBuffer, recordIndex);
                return ConvertToUnNullableArray(values);
            }
        }
        public virtual TimePoint GetTimePoint(DateTime valueTime)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                return GetTimePoint(pBuffer, recordIndex);
            }
        }
        public virtual TimeLine GetTimeLine()
        {
            fixed (byte* pBuffer = buffer)
            {
                return GetTimeLine(pBuffer,
                                   HeaderBufferLength,
                                   TotalBufferLength - SingleBufferLength,
                                   IGNORE_FLAG);
            }
        }
        public virtual TimeLine GetTimeLine(int flag)
        {
            fixed (byte* pBuffer = buffer)
            {
                return GetTimeLine(pBuffer,
                                   HeaderBufferLength,
                                   TotalBufferLength - SingleBufferLength,
                                   flag);
            }
        }
        public virtual TimeLine GetTimeLine(DateTime startTime, DateTime endTime)
        {
            return GetTimeLine(startTime, endTime, 0);
        }
        public virtual TimeLine GetTimeLine(DateTime startTime, DateTime endTime, int flag)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);
            fixed (byte* pBuffer = buffer)
            {
                return GetTimeLine(pBuffer, startIndex, endIndex, flag);
            }
        }
        protected virtual float GetValue(byte* pBuffer, int recordIndex, int fieldIndex)
        {
            CheckFieldIndex(fieldIndex);
            int valueIndex = GetValueIndex(recordIndex, fieldIndex);
            return *((float*)(pBuffer + valueIndex));
        }
        protected virtual float?[] GetArray(byte* pBuffer, int recordIndex)
        {
            float?[] values = new float?[fieldCount];
            for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++)
            {
                int valueIndex = GetValueIndex(recordIndex, fieldIndex);
                float value = *((float*)(pBuffer + valueIndex));
                values[fieldIndex] = value;
            }
            return values;
        }
        protected virtual TimePoint GetTimePoint(byte* pBuffer, int recordIndex)
        {
            TimePoint point = new TimePoint(fieldCount);
            point.Flag = GetFlag(pBuffer, recordIndex);
            point.Time = GetTimeFromRecordIndex(recordIndex);
            point.Values = GetArray(pBuffer, recordIndex);
            return point;
        }
        protected virtual TimeLine GetTimeLine(byte* pBuffer, int startIndex, int endIndex, int flag)
        {            
            TimeLine line = new TimeLine(fieldCount);
            line.Time = valueTime;
            for (int recordIndex = startIndex;
                recordIndex <= endIndex;
                recordIndex += SingleBufferLength)
            {
                if (IsRecordExist(pBuffer, recordIndex))
                {
                    byte bFlag = GetFlag(pBuffer, recordIndex);
                    if (flag > 0 && bFlag != flag) 
                        continue;

                    TimePoint point = GetTimePoint(pBuffer, recordIndex);
                    line.Add(point);
                }
            }
            return line;
        }

        public virtual void SetValue(TimePoint value)
        {
            CheckValueTime(value.Time);
            CheckFieldCount(value.FieldCount);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(value.Time);
                SetFlag(pBuffer, recordIndex, value.Flag);
                SetValue(pBuffer, recordIndex, value.Values);
            }
        }
        public virtual void SetValue(TimeLine value)
        {
            CheckFieldCount(value.FieldCount);
            fixed (byte* pBuffer = buffer)
            {
                foreach (TimePoint point in value.Values)
                {
                    CheckValueTime(point.Time);
                    int recordIndex = GetRecordIndex(point.Time);
                    SetFlag(pBuffer, recordIndex, point.Flag);                    
                    SetValue(pBuffer, recordIndex, point.Values);
                }
            }
        }
        public virtual void SetValue(DateTime valueTime, float value)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                SetValue(pBuffer, recordIndex, 0, value);
            }
        }
        public virtual void SetValue(DateTime valueTime, int fieldIndex, float value)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                SetValue(pBuffer, recordIndex, fieldIndex, value);
            }
        }
        public virtual void SetValue(DateTime valueTime, int flag, int fieldIndex, float value)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                SetFlag(pBuffer, recordIndex, flag);
                SetValue(pBuffer, recordIndex, fieldIndex, value);
            }
        }
        public virtual void SetValue(DateTime valueTime, int flag, float?[] values)
        {
            CheckValueTime(valueTime);
            fixed (byte* pBuffer = buffer)
            {
                int recordIndex = GetRecordIndex(valueTime);
                SetFlag(pBuffer, recordIndex, flag);
                SetValue(pBuffer, recordIndex, values);
            }
        }
        public virtual void SetValue(DateTime valueTime, int flag, float[] values)
        {
            float?[] nullableArray = ConvertToNullableArray(values);
            SetValue(valueTime, flag, nullableArray);
        }
        public virtual void SetValue(DateTime startTime, DateTime endTime, int flag, int fieldIndex, float value)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);
            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = startIndex;
                    recordIndex <= endIndex;
                    recordIndex += SingleBufferLength)
                {
                    SetFlag(pBuffer, recordIndex, flag);
                    SetValue(pBuffer, recordIndex, fieldIndex, value);
                }
            }
        }
        protected virtual void SetValue(byte* pBuffer, int recordIndex, int fieldIndex, float value)
        {
            CheckFieldIndex(fieldIndex);
            int valueIndex = GetValueIndex(recordIndex, fieldIndex);
            *((float*)(pBuffer + valueIndex)) = value;
        }
        protected virtual void SetValue(byte* pBuffer, int recordIndex, float?[] values)
        {            
            CheckFieldCount(values.Length);
            for (int fieldIndex = 0; fieldIndex < values.Length; fieldIndex++)
            {
                int valueIndex = GetValueIndex(recordIndex, fieldIndex);
                float? innerValue = values[fieldIndex];
                if (innerValue.HasValue)
                {
                    *((float*)(pBuffer + valueIndex)) = innerValue.Value;
                }
                else
                {
                    *((float*)(pBuffer + valueIndex)) = float.NaN;
                }
            }
        }

        public virtual void Calculate(Operators oper, int fieldIndex, float operand, DateTime startTime, DateTime endTime)
        {
            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);
            fixed (byte* pBuffer = buffer)
            {
                for (int recordIndex = startIndex;
                    recordIndex <= endIndex;
                    recordIndex += SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        int valueIndex = GetValueIndex(recordIndex, fieldIndex);
                        float value0 = *((float*)(pBuffer + valueIndex));

                        if (float.IsNaN(value0)) value0 = operand;
                        else value0 = Algorithm.Calculate(oper, value0, operand);
                        *((float*)(pBuffer + valueIndex)) = value0;
                    }
                }
            }
        }
        public virtual Binary Calculate(Operators oper, Binary operand, DateTime startTime, DateTime endTime)
        {
            Binary copiedOperand = (Binary)Clone();
            copiedOperand.CalculateFrom(oper, operand, startTime, endTime);
            return copiedOperand;
        }        
        public virtual void CalculateFrom(Operators oper, Binary operand, DateTime startTime, DateTime endTime)
        {
            CheckRegion(startTime, endTime);
            CheckBinary(operand);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);
            fixed (byte* pBuffer = buffer)
            {
                fixed (byte* pOperand = operand.buffer)
                {
                    for (int recordIndex = startIndex;
                        recordIndex <= endIndex;
                        recordIndex += SingleBufferLength)
                    {
                        if (operand.IsRecordExist(pOperand, recordIndex))
                        {
                            if (!IsRecordExist(pBuffer, recordIndex))
                            {
                                byte flag = GetFlag(pOperand, recordIndex);
                                *(pBuffer + recordIndex) = flag;
                            }
                            for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++)
                            {
                                int valueIndex = GetValueIndex(recordIndex, fieldIndex);
                                float value0 = *((float*)(pBuffer + valueIndex));
                                float value1 = *((float*)(pOperand + valueIndex));

                                if (!float.IsNaN(value1))
                                {
                                    float value = float.NaN;
                                    if (!float.IsNaN(value0))
                                    {
                                        value = Algorithm.Calculate(oper, value0, value1); 
                                    }
                                    else
                                    {
                                        value = value1;
                                    }
                                    *((float*)(pBuffer + valueIndex)) = value;
                                }
                            }
                        }
                    }
                }
            }
        }

        public virtual void SwitchInterpolate(int fieldIndex, int flag, DateTime startTime, DateTime endTime)
        {
            if (recordCount == 0) return;

            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);
            fixed (byte* pBuffer = buffer)
            {
                // 为数据头部进行插值
                startIndex = HeadInterpolate(pBuffer, fieldIndex, flag, startIndex, endIndex);

                // 为数据尾部进行插值
                endIndex = TailInterpolate(pBuffer, fieldIndex, flag, startIndex, endIndex);

                // 如果开始索引和结束索引重合，则退出插值
                if (startIndex == endIndex)
                    return;

                // 为中间数据进行线性插值
                int prevIndex = -1; float prevValue = 0.0f;
                for (int recordIndex = startIndex;
                    recordIndex <= endIndex;
                    recordIndex += SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        float value = GetValue(pBuffer, recordIndex, fieldIndex);
                        if (!float.IsNaN(value))
                        {
                            if (prevIndex != -1)
                            {
                                for (int i = prevIndex + SingleBufferLength;
                                    i < recordIndex;
                                    i += SingleBufferLength)
                                {
                                    SetFlag(pBuffer, i, flag);
                                    SetValue(pBuffer, i, fieldIndex, prevValue);
                                }
                            }
                            prevIndex = recordIndex;
                            prevValue = value;
                        }
                    }
                }
            }
        }
        public virtual void LinearInterpolate(int fieldIndex, int flag, DateTime startTime, DateTime endTime)
        {
            if (recordCount == 0) return;

            CheckRegion(startTime, endTime);

            int startIndex = GetRecordIndex(startTime);
            int endIndex = GetRecordIndex(endTime);
            fixed (byte* pBuffer = buffer)
            {
                // 为数据头部进行插值
                startIndex = HeadInterpolate(pBuffer, fieldIndex, flag, startIndex, endIndex);

                // 为数据尾部进行插值
                endIndex = TailInterpolate(pBuffer, fieldIndex, flag, startIndex, endIndex);

                // 如果开始索引和结束索引重合，则退出插值
                if (startIndex == endIndex)
                    return;

                // 为中间数据进行线性插值
                int prevIndex = -1; float prevValue = 0.0f;
                for (int recordIndex = startIndex;
                    recordIndex <= endIndex;
                    recordIndex += SingleBufferLength)
                {
                    if (IsRecordExist(pBuffer, recordIndex))
                    {
                        float value = GetValue(pBuffer, recordIndex, fieldIndex);
                        if (!float.IsNaN(value))
                        {
                            if (prevIndex != -1)
                            {
                                int diffIndex = (recordIndex - prevIndex) / SingleBufferLength;
                                float factor = (value - prevValue) / diffIndex;

                                for (int i = prevIndex + SingleBufferLength;
                                    i < recordIndex;
                                    i += SingleBufferLength)
                                {
                                    prevValue += factor;
                                    SetFlag(pBuffer, i, flag);
                                    SetValue(pBuffer, i, fieldIndex, prevValue);
                                }
                            }
                            prevIndex = recordIndex;
                            prevValue = value;
                        }
                    }
                }
            }
        }
        private int HeadInterpolate(byte* pBuffer, int fieldIndex, int flag, int startIndex, int endIndex)
        {
            // 查找开始时间以后第一个有效数据
            for (int recordIndex = startIndex;
                recordIndex <= endIndex;
                recordIndex += SingleBufferLength)
            {
                if (IsRecordExist(pBuffer, recordIndex))
                {
                    float value = GetValue(pBuffer, recordIndex, fieldIndex);
                    if (!float.IsNaN(value))
                    {
                        for (int i = startIndex; i < recordIndex; i += SingleBufferLength)
                        {
                            SetFlag(pBuffer, i, flag);
                            SetValue(pBuffer, i, fieldIndex, value);
                        }
                        return recordIndex;
                    }
                }
            }
            return endIndex;
        }
        private int TailInterpolate(byte* pBuffer, int fieldIndex, int flag, int startIndex, int endIndex)
        {
            // 查找结束时间以前最后一个有效数据
            for (int recordIndex = endIndex;
                recordIndex >= startIndex;
                recordIndex -= SingleBufferLength)
            {
                if (IsRecordExist(pBuffer, recordIndex))
                {
                    float value = GetValue(pBuffer, recordIndex, fieldIndex);
                    if (!float.IsNaN(value))
                    {
                        for (int i = recordIndex + SingleBufferLength;
                            i <= endIndex; 
                            i += SingleBufferLength)
                        {
                            SetFlag(pBuffer, i, flag);
                            SetValue(pBuffer, i, fieldIndex, value);
                        }
                        return recordIndex;
                    }
                }
            }
            return startIndex;
        }

        protected abstract int GetRecordCount();
        protected abstract byte[] CreateBuffer();

		public virtual int GetTimeIndex(DateTime valueTime)
		{
			return (valueTime.Hour * 60 + valueTime.Minute) / interval;
		}
        public abstract int GetRecordIndex(DateTime valueTime);
        public abstract int GetRecordIndex(int timeIndex);
        public virtual int GetValueIndex(DateTime valueTime, int fieldIndex)
        {
            int recordIndex = GetRecordIndex(valueTime);
            return GetValueIndex(recordIndex, fieldIndex);
        }
        protected virtual int GetValueIndex(int recordIndex, int fieldIndex)
        {
            return recordIndex + sizeof(byte) + sizeof(float) * fieldIndex;
        }
        protected virtual DateTime GetTimeFromTimeIndex(int timeIndex)
        {
            return valueTime.AddMinutes(timeIndex);
        }
        protected abstract DateTime GetTimeFromRecordIndex(int recordIndex);

        protected virtual void ThrowCheck(int interval, int fieldCount)
        {
            if (interval <= 0 || interval > MINUTES_PER_DAY)
                throw new ArgumentOutOfRangeException("Interval 范围为 1 ~ " + MINUTES_PER_DAY);
            if (fieldCount <= 0)
                throw new ArgumentOutOfRangeException("FieldCount 必须大于 0");
        }
        protected virtual void CheckRegion(DateTime startTime, DateTime endTime)
        {
            CheckValueTime(startTime);
            CheckValueTime(endTime);
            if (startTime > endTime)
                throw new ArgumentException("StartTime 大于 EndTime");
            int startIndex = GetTimeIndex(startTime);
            int endIndex = GetTimeIndex(endTime);
            if (startIndex < StartTimeIndex)
                throw new ArgumentOutOfRangeException("StartTime 超出最小时间索引号");            
            if (endIndex > EndTimeIndex)
                throw new ArgumentOutOfRangeException("EndTime 超出最大时间索引号");
        }
        protected virtual void CheckValueTime(DateTime valueTime)
        {
            if (valueTime.Minute % interval != 0)
                throw new ArgumentException("ValueTime 与 Interval 不匹配");
        }        
        protected virtual void CheckFieldIndex(int fieldIndex)
        {
            if (fieldIndex < 0)
                throw new ArgumentException("FieldIndex 必须大于等于 0");
            if ((fieldIndex + 1) > fieldCount)
                throw new ArgumentException("FieldIndex 必须小于 FieldCount");
        }
        protected virtual void CheckFieldCount(int fieldCount)
        {
            if (fieldCount <= 0)
                throw new ArgumentException("FieldCount 必须大于 0");
            if (this.fieldCount != fieldCount)
                throw new ArgumentException("FieldCount 不匹配");
        }
        protected virtual void CheckFlag(int flag)
        {
            if (flag <= 0 || flag > 255)
                throw new ArgumentException("Flag 必须在 1 ~ 255 之间");
        }
        protected virtual void CheckBuffer(byte[] buffer)
        {
            if (buffer == null)
                throw new ArgumentNullException("Buffer 为空");
            if (buffer.Length != TotalBufferLength)
                throw new ArgumentException("Buffer 长度不匹配");
        }
        protected virtual void CheckValues(float?[] values)
        {
            if (values == null)
                throw new ArgumentNullException("Values 数组为空");
            CheckFieldCount(values.Length);
        }
        protected virtual void CheckBinary(Binary binary)
        {
            if (binary.fieldCount != fieldCount)
                throw new ArgumentException("Binary 的字段个数与当前的 FieldCount 不同");
            if (binary.interval != interval)
                throw new ArgumentException("Binary 的时间间隔与当前的 Interval 不同");
            if (binary.TotalBufferLength != TotalBufferLength)
                throw new ArgumentException("Binary 的数据长度与当前的 TotalBufferLength 不同");
        }
        protected float?[] ConvertToNullableArray(float[] array)
        {
            return Array.ConvertAll<float, float?>(array,
                new Converter<float, float?>(
                    delegate(float value)
                    {
                        return value;
                    }));
        }
        protected float[] ConvertToUnNullableArray(float?[] array)
        {
            return Array.ConvertAll<float?, float>(array,
                new Converter<float?, float>(
                    delegate(float? value)
                    {
                        if (value.HasValue) return value.Value;
                        return float.NaN;
                    }));
        }

        #region ICloneable Members

        public object Clone()
        {
            this.BeginEdit();
            Binary binary = Utils.Clone<Binary>(this);
            binary.CachePositionIndex = -1;
            this.EndEdit();

            return binary;
        }

        #endregion

        #region IIterator Members

        private int step;
        private int[] operTypes;

        int IIterator.Step
        {
            get { return step; }
            set { step = value; }
        }

        int[] IIterator.OperTypes
        {
            get { return operTypes; }
            set { operTypes = value; }
        }

        bool IIterator.MatchOperType(int flag)
        {            
            if (flag == 255) return false;
            if (operTypes == null || operTypes.Length == 0 || flag == operTypes[0])
                return true;
            return (Array.BinarySearch<int>(operTypes, flag) >= 0);
        }

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            ((IIterator)this).Reset();
            return this;
        }

        #endregion

        #region IEnumerator Members

        [NonSerialized]
        private ResultRecordRow _Row;
        private int PrevTimeIndex;
        private int PrevRecordCount;

        object IEnumerator.Current
        {
            get { return _Row; }
        }

        bool IEnumerator.MoveNext()
        {
            fixed (byte* pBuffer = buffer)
            {
                while (PrevTimeIndex <= EndTimeIndex &&
                       PrevRecordCount >= 0)
                {
                    int recordIndex = GetRecordIndex(PrevTimeIndex);
                    int flag = *(pBuffer + recordIndex);
                    if (((IIterator)this).MatchOperType(flag))
                    {
                        _Row.OperType = flag;
                        _Row.ValueTime = GetTimeFromTimeIndex(PrevTimeIndex);
                        for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++)
                        {
                            int valueIndex = GetValueIndex(recordIndex, fieldIndex);
                            _Row.Values[fieldIndex] = *((float*)(pBuffer + valueIndex));
                        }
                        PrevTimeIndex += step;
                        PrevRecordCount -= 1;                        
                        return true;
                    }
                    PrevTimeIndex += step;
                }                
            }
            return false;
        }

        void IEnumerator.Reset()
        {
            _Row.Values = new float?[fieldCount];
            PrevTimeIndex = StartTimeIndex;
            PrevRecordCount = recordCount;
        }

        #endregion

        #endregion
    }
}
